#######################################################
# Example of PingPong coupled DEVS using DEVS player
# Author: moonho.hwang@gmail.com
#   Date: Oct.19.2011
#######################################################
from XSY.DEVS.FSDEVS import *
from XSY.DEVS.CoupledDEVS import *
from XSY.Set.Interval import *
#from XSY.GraphVizy.GraphVizy import *
from XSY.DEVS.VeriEngine import VeriEngine
from XSY.DEVS.SimEngine import SimEngine

class Player(FSDEVS):
   def __init__(m, n, iv, parent=None):
      '''constructor'''
      FSDEVS.__init__(m, n, parent) 
      m.iv = iv

      m.addInputPorts('?r', "?stop")
      m.addOutputPorts('!s')

   def rv_delta_0(m):
      '''random initial state'''
      return DRV({'S':0.5, 'W':0.5} )
      #return DRV({m.iv:1}) # m.iv is the given inital state

   def rv_tau(m):
      '''random lifespan scheduling function'''
      if m.phase == 'S':
         return TInterval(.2,.3) # continuous random variable distributed uniformly 
      else:
         return DRV({float('inf'):1}) # discrete random variable

   def rv_delta_x(m, x):
      '''random external transition function'''
      if x.port == m.IP['?r'] and m.phase == 'W':
         return DRV({(True,'S'):1})
      elif x.port == m.IP['?stop']:
         return DRV({(True,'W'):1})
      else:
         return DRV({(False,m.phase):1})
               
   def rv_delta_y(m):
      '''random output and internal transition function'''
      if m.phase == 'S':
         y = PortValue(m.OP["!s"])
         return DRV({(y,'W'):1})
   
   def get_state(m):
      '''get the state'''
      return m.phase

   def set_state(m, s):
      '''set the state as s'''
      m.phase = s
 
def makeModel():
   md1 = Player('A', 'S')
   md2 = Player('B', 'W')

   cm = CoupledDEVS("PingPong")
   cm.addInputPorts("?stop")
   cm.addComponents(md1, md2)
   cm.addCouples((md1.OP["!s"], md2.IP["?r"]), (md2.OP["!s"], md1.IP["?r"]))
   cm.addCouples((cm.IP["?stop"], md2.IP["?stop"]), (md2.IP["?stop"], md1.IP["?stop"]))
   return cm

def runSimulation(md):
   engine = SimEngine(md)

   #---- setting StepByStep and DES simulation only ----
   #engine.StepByStep = True
   engine.sfactor = float('inf')
   #----------------------------------------------------
   engine.runInteractiveMenu()

def runVerification(md):
   X = []
   #X.append(PortValue(md.IP['?stop']))
   VE = VeriEngine(md, X, None, None)
   VE.runtimeInteractiveMenu()

if __name__ == '__main__':
   md = makeModel()
   print 'isNetworkOf(Player)=', md.isNetworkOf(Player)

   c = True
   while c:
      s = raw_input('[s]im, [v]eri, e[x]it>')
      if s == 's' or s == 'sim': 
         runSimulation(md)
      elif s == 'v' or s == 'veri':
         runVerification(md)
      elif s == 'x' or s == 'exit':
         c = False
      else:
         print('%s is an invalid input!'%s)
      
   print "good bye~!" 
